package iit.projects.etaxi.model.dao;

import java.util.List;

import iit.projects.etaxi.model.dto.CitySCDO;
import iit.projects.etaxi.model.entity.City;
import iit.projects.etaxi.model.exception.CityNotFoundException;
import iit.projects.etaxi.model.exception.DuplicateCityException;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public class HibernateCityDao extends HibernateDaoSupport implements CityDao {

	final Logger log = LoggerFactory.getLogger(HibernateCityDao.class);
	
	@Override
	public City addCity(City city) throws DuplicateCityException {
	
		if(log.isDebugEnabled()){
			log.debug("Going to save City : " + city.getCode());
		}
		Session session = getSession(false);
		
		try{
			City duplicate = (City)session.get(City.class, city.getCode());
			if(duplicate != null){
				throw new DuplicateCityException(new String[]{city.getCode()});
			}
			duplicate = findCityByName(city.getName());
			if(duplicate != null){
				throw new DuplicateCityException(new String[]{city.getName()});
			}
			session.save(city);
			
			return (City)session.get(City.class, city.getCode());
		}catch(HibernateException ex){
			throw convertHibernateAccessException(ex);
		}
	}
	
	@SuppressWarnings("unchecked")
	public List<City> findCities(CitySCDO citySCDO){
		if(log.isDebugEnabled()){
			log.debug("Finding Cities");
		}
		
		List<City> list = null;
		Session session = getSession(false);
		
		try {
			String code = citySCDO.getCode();
			String name = citySCDO.getName();

			Criteria criteria = session.createCriteria(City.class);
			if (code != null && !code.isEmpty()) {
				if (!code.contains("%")) {
					code = "%" + code + "%";
				}
				criteria.add(Restrictions.like("code", code));
			}
			if (name != null && !name.isEmpty()) {
				if (!name.contains("%")) {
					name = "%" + name + "%";
				}
				criteria.add(Restrictions.like("name", name));
			}

			criteria.addOrder(Order.asc("code"));
			list = criteria.list();
		} catch (HibernateException ex) {
			throw convertHibernateAccessException(ex);
		}
		return list;
	}
	
	@Override
	public City updateCity(City city){
		if (log.isDebugEnabled()) {
			log.debug("Updating City " + city.getCode());
		}
		Session session = getSession(false);
		try {
			session.update(city);
			
			return (City)session.get(City.class, city.getCode());
		} catch (HibernateException ex) {
			throw convertHibernateAccessException(ex);
		}
	}
	
	@Override
	public void deleteCity(City city){
		if (log.isDebugEnabled()) {
			log.debug("Deleting City " + city.getCode());
		}
		Session session = getSession(false);
		try {
			session.delete(city);
		} catch (HibernateException ex) {
			throw convertHibernateAccessException(ex);
		}
	}
	
	@Override
	public City findByPrimaryKey(String code) throws CityNotFoundException{
		if (log.isDebugEnabled()) {
			log.debug("Going to find City by Code " + code);
		}
		
		Session session = getSession(false);
		try {
			City city = (City)session.get(City.class, code);
			if(city == null){
				throw new CityNotFoundException();
			}
			return city;
		} catch (HibernateException ex) {
			throw convertHibernateAccessException(ex);
		}
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public City findCityByName(String name)
	{
		if(log.isDebugEnabled()){
			log.debug("Going to find Driver by city name " + name);
		}
		
		Session session = getSession(false);
		
		try{
			Criteria criteria = session.createCriteria(City.class);
			criteria.add(Restrictions.eq("name", name));
			
			List<City> list = criteria.list();
			if(list != null && !list.isEmpty()){
				return list.iterator().next();
			}
			else{
				return null;
			}
		}catch(HibernateException ex){
			throw convertHibernateAccessException(ex);
		}
	}

}
